﻿// Created by amoylel on 11/17/2017.
// Copyright (c) 2017 amoylel All rights reserved.

#ifndef AMO_SQLMESSAGEEMITTER_HPP__
#define AMO_SQLMESSAGEEMITTER_HPP__

#include <amo/ipc/message_launcher.hpp>
#include <amo/transfer/sqlite_transfer.hpp>

namespace amo {
    class sqlite_emitter : protected message_launcher {
    public:
        sqlite_emitter(std::shared_ptr<sqlite_transfer> pDB)
            : m_pDB(pDB) {
            
        }
        
        template<typename ... Args>
        ipc_message::SmartType createSqlMessage(const std::string& name, Args... args) {
            msg.reset(new ipc_message());
            createIPCMessage<Args ...>(name, IPC_NATIVE_SYNC_EXECUTE, args...);
            return msg;
        }
        
        template<typename ... Args>
        amo::any import(Args... args) {
            ipc_message::SmartType sql = createSqlMessage<Args ...>("import", args...);
            return  m_pDB->import(sql);
        }
        
        
        template<typename ... Args>
        amo::any execute(Args... args) {
            ipc_message::SmartType sql = createSqlMessage<Args ...>("execute", args...);
            return  m_pDB->execute(sql);
        }
        
        template<typename ... Args>
        amo::any insert(Args... args) {
            ipc_message::SmartType sql = createSqlMessage<Args ...>("insert", args...);
            return  m_pDB->insert(sql);
        }
        
        template<typename ... Args>
        amo::any insertOrUpdate(Args... args) {
            ipc_message::SmartType sql = createSqlMessage<Args ...>("insertOrUpdate",
                                         args...);
            return  m_pDB->insertOrUpdate(sql);
        }
        
        
        template<typename ... Args>
        amo::any update(Args... args) {
            ipc_message::SmartType sql = createSqlMessage<Args ...>("update", args...);
            return  m_pDB->update(sql);
        }
        
        template<typename ... Args>
        amo::any backup(Args... args) {
            ipc_message::SmartType sql = createSqlMessage<Args ...>("backup", args...);
            return  m_pDB->backup(sql);
        }
        
        template<typename ... Args>
        amo::any query(Args... args) {
            ipc_message::SmartType sql = createSqlMessage<Args ...>("query", args...);
            return  m_pDB->query(sql);
        }
        
        
        template<typename ... Args>
        amo::any remove(Args... args) {
            ipc_message::SmartType sql = createSqlMessage<Args ...>("remove", args...);
            return  m_pDB->remove(sql);
        }
        
        template<typename ... Args>
        amo::any queryCount(Args... args) {
            ipc_message::SmartType sql = createSqlMessage<Args ...>("queryCount", args...);
            return  m_pDB->queryCount(sql);
        }
        
        template<typename ... Args>
        amo::any getLastInsertRowID(Args... args) {
            ipc_message::SmartType sql = createSqlMessage<Args ...>("getLastInsertRowID",
                                         args...);
            return  m_pDB->getLastInsertRowID(sql);
        }
        
        template<typename ... Args>
        amo::any containsTable(Args... args) {
            ipc_message::SmartType sql = createSqlMessage<Args ...>("containsTable",
                                         args...);
            return  m_pDB->containsTable(sql);
        }
        
        template<typename T, typename ... Args>
        std::shared_ptr<T> load(Args... args) {
            amo::any val = queryOne<T, Args...>(args...);
            
            if (val.is<amo::undefined>()) {
                return std::shared_ptr<T>();
            }
            
            amo::u8json data = val;
            return T::fromJson(data);
        }
        
        template<typename ... Args>
        amo::any queryOne(Args... args) {
        
            amo::any val = query<Args...>(args...);
            
            if (val.is<amo::undefined>()) {
                return amo::undefined();
            }
            
            amo::u8json json = val;
            std::vector<amo::json_value> arr = json.getJson("data").to_value_array();
            
            if (arr.size() < 1) {
                return amo::undefined();
            }
            
            return amo::u8json(arr[0]);
        }
        
    public:
        int getFieldStyle() const {
            return m_pDB->getFieldStyle();
        }
        void setFieldStyle(int val) {
            return m_pDB->setFieldStyle(val);
        }
        
    private:
    
        virtual bool exchange(int nPipeID, ipc_message::SmartType msg) override {
            return true;
        }
        
        
        virtual amo::any waitResult(int nPipeID, int nMessageID) override {
            return amo::undefined();
        }
        
        
        virtual bool sendMessage(ipc_message::SmartType msg) override {
            return true;
        }
        
    private:
        std::shared_ptr<sqlite_transfer> m_pDB;
        
    };
}

#endif // AMO_SQLMESSAGEEMITTER_HPP__